# -*- coding: utf-8 -*-
# =============================================================================
#     FileName:
#         Desc:
#       Author:
#        Email:
#     HomePage:
#      Version:
#   LastChange:
#      History:
# =============================================================================
import logging.handlers
from collections import namedtuple

import redis

from utils.common_config import CommonConfig
from utils.top_max_heap import TopMaxHeapItem, TopMaxHeap

logger = logging.getLogger(name=CommonConfig.app_name)

RedisConfig = namedtuple("RedisConfig", ["redis_host", "redis_port", "redis_password", "redis_db"])


class BigKeyScanner(object):
    def __init__(self, redis_config: RedisConfig, min_key_size=1 * 1024,
                 top_key_size=100, top_key_type="all", scan_key_count=0):
        self.redis_config = redis_config
        self.min_key_size = min_key_size
        self.top_key_size = top_key_size
        self.top_key_type = top_key_type
        self.top_heap = TopMaxHeap(top_size=top_key_size)
        self.scan_key_count = scan_key_count
        self.scan_key_index = 0

    def get_redis_conn(self):
        return redis.StrictRedis(
            host=self.redis_config.redis_host,
            port=self.redis_config.redis_port,
            password=self.redis_config.redis_password,
            db=self.redis_config.redis_db
        )

    @classmethod
    def get_key_info_by_string(cls, key_info_str: str):
        key_info = {}
        sub_items = key_info_str.split(" ")
        for sub_item in sub_items:
            if sub_item.find(":") > 0:
                tmp_list = sub_item.split(":")
                key_info[tmp_list[0]] = tmp_list[1]
        return key_info

    def get_batch_key_info(self, key_name_list):
        redis_conn = self.get_redis_conn()
        key_info_list = list()
        with redis_conn.pipeline(transaction=False) as pipe:
            for key_name in key_name_list:
                pipe.memory_usage(key=key_name)
            key_info_list = pipe.execute()

        return key_info_list

    def scan_redis_keys(self, scan_count=100):
        redis_conn = self.get_redis_conn()
        start_cursor = 0
        while True:
            if 0 < self.scan_key_count < self.scan_key_index:
                break
            self.scan_key_index += scan_count
            if self.scan_key_index % 10000 == 0:
                logger.info("完成第{}个KEY扫描".format(self.scan_key_index))
            next_cursor, key_name_list = redis_conn.scan(cursor=start_cursor, match="*", count=scan_count)
            if next_cursor != 0:
                start_cursor = next_cursor
            else:
                break
            key_info_list = self.get_batch_key_info(key_name_list=key_name_list)
            if len(key_info_list) != len(key_name_list):
                logger.info("未能获取到所有key的信息，跳过本次所有KEY")
                continue
            for key_index in range(0, len(key_info_list)):
                key_memory = key_info_list[key_index]
                if key_memory < self.min_key_size:
                    continue
                key_name = key_name_list[key_index].decode("utf-8")
                key_data = "key_name: {},key_memory: {}".format(key_name, key_memory)
                top_item = TopMaxHeapItem(item_key=key_memory, item_data=key_data)
                self.top_heap.push_item(top_item)
        self.show_big_keys()

    def show_big_keys(self):
        top_items = self.top_heap.get_top_items()
        logger.info("共获取到{}个大KEY(超过{})".format(len(top_items), self.min_key_size))
        for top_item in top_items:
            logger.info(top_item.item_data)
        pass
